#include <cmath>
#include <cstdlib>
#include <lua.hpp>

#define ran(a, b) (rand() % (b - a + 1)) + a  //生成[a,b]内的整数

struct index {
    int i;
    int j;
};

int list[5][5];   //存储每个格中的数字
int shine[5][5];  //存储格内数字是否变化

/*检查位置是否处于定义的存储范围中*/
int inlist(int i, int j) {
    if (i == 0 && j > 2) {
        return 0;
    } else if (i == 1 && j > 3) {
        return 0;
    } else if (i == 2 && j > 4) {
        return 0;
    } else if (i == 3 && j < 1) {
        return 0;
    } else if (i == 4 && j < 2) {
        return 0;
    } else if (i < 0 || i > 4) {
        return 0;
    }
    if (j < 0 || j > 4) {
        return 0;
    }
    return 1;
}

void swap(int i1, int j1, int i2, int j2) {
    int temp = list[i1][j1];
    list[i1][j1] = list[i2][j2];
    list[i2][j2] = temp;
    return;
}

/*在斜纵轴上移动，正方向为右上方，返回中止位置*/
index mov_svet(int i, int j, int p) {
    while (list[i][j] && inlist(i - p, j)) {  //检查下一格是否还在表中
        if (list[i - p][j] == 0) {
            swap(i, j, i - p, j);
            i -= p;
            continue;
        } else if (list[i - p][j] == list[i][j]) {
            list[i - p][j] += list[i][j];
            list[i][j] = 0;
            i -= p;
            break;
        } else {
            break;
        }
    }
    index position;
    position.i = i;
    position.j = j;
    return position;
}

/*在反斜纵轴上移动，正方向为左上方*/
index mov_bsvet(int i, int j, int p) {
    while (list[i][j] && inlist(i - p, j - p)) {
        if (list[i - p][j - p] == 0) {
            swap(i, j, i - p, j - p);
            i -= p;
            j -= p;
            continue;
        } else if (list[i - p][j - p] == list[i][j]) {
            list[i - p][j - p] += list[i][j];
            list[i][j] = 0;
            i -= p;
            j -= p;
            break;
        } else {
            break;
        }
    }
    index position;
    position.i = i;
    position.j = j;
    return position;
}

/*在横轴上移动，正方向为右方*/
index mov_hor(int i, int j, int p) {
    while (list[i][j] && inlist(i, j + p)) {
        if (list[i][j + p] == 0) {
            swap(i, j, i, j + p);
            j += p;
            continue;
        } else if (list[i][j + p] == list[i][j]) {
            list[i][j + p] += list[i][j];
            list[i][j] = 0;
            j += p;
            break;
        } else {
            break;
        }
    }
    index position;
    position.i = i;
    position.j = j;
    return position;
}

/*向指定的方向合并，1为右上方，顺时针递增，返回是否合并成功*/
int slip(lua_State* L) {
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            shine[i][j] = 0;
        }
    }
    int win = 0;
    int dir = lua_tonumber(L, 1);
    switch (dir) {
        case 1:
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    if (inlist(i, j)) {
                        index end = mov_svet(i, j, 1);
                        if (!(end.i == i && end.j == j)) {
                            shine[i][j] = 1;
                            shine[end.i][end.j] = 1;
                            if (list[end.i][end.j] == 2048) {
                                win = 1;
                            }
                        }
                    }
                }
            }
            break;
        case 2:
            for (int j = 4; j >= 0; j--) {
                for (int i = 0; i < 5; i++) {
                    if (inlist(i, j)) {
                        index end = mov_hor(i, j, 1);
                        if (!(end.i == i && end.j == j)) {
                            shine[i][j] = 1;
                            shine[end.i][end.j] = 1;
                            if (list[end.i][end.j] == 2048) {
                                win = 1;
                            }
                        }
                    }
                }
            }
            break;
        case 3:
            for (int i = 4; i >= 0; i--) {
                for (int j = 0; j < 5; j++) {
                    if (inlist(i, j)) {
                        index end = mov_bsvet(i, j, -1);
                        if (!(end.i == i && end.j == j)) {
                            shine[i][j] = 1;
                            shine[end.i][end.j] = 1;
                            if (list[end.i][end.j] == 2048) {
                                win = 1;
                            }
                        }
                    }
                }
            }
            break;
        case 4:
            for (int i = 4; i >= 0; i--) {
                for (int j = 0; j < 5; j++) {
                    if (inlist(i, j)) {
                        index end = mov_svet(i, j, -1);
                        if (!(end.i == i && end.j == j)) {
                            shine[i][j] = 1;
                            shine[end.i][end.j] = 1;
                            if (list[end.i][end.j] == 2048) {
                                win = 1;
                            }
                        }
                    }
                }
            }
            break;
        case 5:
            for (int j = 0; j < 5; j++) {
                for (int i = 0; i < 5; i++) {
                    if (inlist(i, j)) {
                        index end = mov_hor(i, j, -1);
                        if (!(end.i == i && end.j == j)) {
                            shine[i][j] = 1;
                            shine[end.i][end.j] = 1;
                            if (list[end.i][end.j] == 2048) {
                                win = 1;
                            }
                        }
                    }
                }
            }
            break;
        case 6:
            for (int i = 0; i < 5; i++) {
                for (int j = 0; j < 5; j++) {
                    if (inlist(i, j)) {
                        index end = mov_bsvet(i, j, 1);
                        if (!(end.i == i && end.j == j)) {
                            shine[i][j] = 1;
                            shine[end.i][end.j] = 1;
                            if (list[end.i][end.j] == 2048) {
                                win = 1;
                            }
                        }
                    }
                }
            }
            break;
    }
    int changed = 0;
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            changed += shine[i][j];
        }
    }
    lua_pushnumber(L, changed / 2);
    lua_pushnumber(L, win);
    return 2;
}

/*初始化存储表*/
int init(lua_State* L) {
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            list[i][j] = 0;
        }
    }
    list[0][3] = -1;
    list[0][4] = -1;
    list[1][4] = -1;
    list[3][0] = -1;
    list[4][0] = -1;
    list[4][1] = -1;
    /*
        list[0][1] = 1;
        list[1][1] = 1;
        list[2][1] = 1;
        list[3][1] = 1;*/
    list[2][2] = 1024;
    list[2][3] = 1024;
    return 0;
}

/*返回指定位置的数字*/
int num(lua_State* L) {
    int i = lua_tonumber(L, 1);
    int j = lua_tonumber(L, 2);
    lua_pushnumber(L, list[i][j]);
    return 1;
}

/*返回指定位置是否发生变化*/
int shi(lua_State* L) {
    int i = lua_tonumber(L, 1);
    int j = lua_tonumber(L, 2);
    lua_pushnumber(L, shine[i][j]);
    return 1;
}

/*在表中随机生成一个数字*/
int gene(lua_State* L) {
    int i, j;
    while (1) {
        i = ran(0, 5);
        j = ran(0, 5);
        if (inlist(i, j) && list[i][j] == 0) {
            list[i][j] = pow(2, ran(1, 4));
            break;
        }
    }
    shine[i][j] = 1;
    return 0;
}

extern "C" {
int luaopen_lib_dll_api(lua_State* L) {
    constexpr luaL_Reg functions[] = {{"slip", slip}, {"init", init},
                                      {"num", num},   {"shi", shi},
                                      {"gene", gene}, {NULL, NULL}};
    luaL_register(L, "api", functions);
    return 1;
}
}